﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;

using Log;
using ilibrary.source.model.metasearch;


namespace ilibrary.source.model
{
    public abstract class EBook : IEbook
    {
        #region Variables
        private EventLog log = new EventLog("ILibrary", "EBook");

        #region DataField
        protected int id;
        protected string filePath;
        protected string title;
        protected string authors;
        protected string publisher;
        protected string description;
        protected string isbn;
        protected string imageUrl;
        protected string summary;
        protected List<string> tags;
        #endregion

        #region Additionnal DataField
        protected string directory;
        protected long size;
        protected string type;
        protected string toc;
        #endregion

        #endregion

        #region Constructors
        protected EBook()
        {
        }
        protected EBook(int id, string filePath)
        {
            this.id = id;
            this.filePath = filePath;
            
            // Additionnal DataField Initialisation
            this.directory = Path.GetDirectoryName(filePath);
            this.size = -1;
            this.type = Path.GetExtension(filePath).Substring(1);//supprimer le point initial 
        }
        #endregion

        #region DataField
        public int Id
        {
            get { return id; }
        }

        public string Filepath
        {
            get { return this.filePath; }
            set
            {
                if (string.Compare(
                    Path.GetDirectoryName(value),
                    this.Directory) == 0)
                    if (string.Compare(
                        Path.GetExtension(value),
                        string.Concat(".",this.Type)) == 0)
                    {
                        this.filePath = value;
                        SqlliteDB.Instance.updateEbookPath(Id, value);
                    }
                    else
                        throw new OperationCanceledException("Extension has been modified");
                else
                    throw new OperationCanceledException("FullPath has been modified");
            }
        }

        public string Title
        {
            get
            {
                this.title = SqlliteDB.Instance.selectEBookTitle(this.Id);
                if (string.IsNullOrEmpty(this.title))
                    this.title = System.IO.Path.GetFileNameWithoutExtension(this.Filepath);
                return this.title;
            }
            set
            {
                if (string.IsNullOrEmpty(value))
                    throw new OperationCanceledException("Title can't be empty");
                else
                {
                    this.title = value;
                    SqlliteDB.Instance.updateEbookTitle(Id, value);
                }
            }
        }

        public string Authors
        {
            get
            {
                this.authors = SqlliteDB.Instance.selectEBookAuthors(this.Id);
                return this.authors;
            }
            set
            {
                this.authors = value;
                SqlliteDB.Instance.updateEbookAuthors(Id, value);
            }
        }

        public string Publisher
        {
            get
            {
                this.publisher = SqlliteDB.Instance.selectEBookPublisher(this.Id);
                return this.publisher;
            }
            set
            {
                this.publisher = value;
                SqlliteDB.Instance.updateEbookPublisher(id, value);
            }
        }

        public string Description
        {
            get
            {
                this.description = SqlliteDB.Instance.selectEBookDescription(this.Id);
                return this.description;
            }
            set
            {
                this.description = value;
                SqlliteDB.Instance.updateEbookDescription(id, value);
            }
        }

        public string ISBN
        {
            get
            {
                this.isbn = SqlliteDB.Instance.selectEBookISBN(this.Id);
                return this.isbn;
            }
            set
            {
                this.isbn = value;
                SqlliteDB.Instance.updateEbookISBN(id, value);
            }
        }

        public string ImageUrl
        {
            get
            {
                this.imageUrl = SqlliteDB.Instance.selectEBookImageUrl(this.Id);
                return this.imageUrl;
            }
            set
            {
                this.imageUrl = value;
                SqlliteDB.Instance.updateEbookImageUrl(id, value);
            }
        }

        public string Summary
        {
            get
            {
                this.summary = SqlliteDB.Instance.selectEBookSummary(this.Id);
                return this.summary;
            }
            set
            {
                this.summary = value;
                SqlliteDB.Instance.updateEbookSummary(id, value);
            }
        }

        public List<string> Tags
        {
            get
            {
                if (this.tags == null)
                    this.tags = SqlliteDB.Instance.selectTagsForEBook(this.Id);
                return this.tags;
            }
        }
        #endregion

        #region Additionnal DataField
        public string Directory
        {
            get { return this.directory; }
        }

        public long Size
        {
            get
            {
                if (size == -1)
                {
                    FileInfo fi = new FileInfo(this.Filepath);
                    this.size = fi.Length;
                }
                return size;
            }
        }

        public string SizeToString
        {
            get
            {
                long sizeInByte = this.Size;
                long sizeInKByte = sizeInByte / 1024;
                long sizeInMByte = sizeInKByte / 1024;

                StringBuilder size = new StringBuilder();
                if (sizeInMByte != 0)
                {
                    size.Append(sizeInMByte.ToString());
                    size.Append(",");
                    size.Append((sizeInKByte % 1024).ToString());
                    size.Append("Mo");
                }
                else if (sizeInKByte != 0)
                {
                    size.Append(sizeInKByte.ToString());
                    size.Append(",");
                    size.Append((sizeInByte % 1024).ToString());
                    size.Append("Ko");
                }
                else
                {
                    size.Append(sizeInByte.ToString());
                    size.Append("octets");
                }
                return size.ToString();
            }
        }

        public string Type
        {
            get { return this.type; }
        }

        public string TOC
        {
            get
            {
                return this.toc;
            }
        }

        public string getTOC(IEBookReadingHandler readingHandler)
        {

            //on essaie de charger le toc ssi toc est null.
            //quand on essaie et qu'on n'arrive pas à charger un toc
            //toc est mis string.Empty
            if (this.toc == null)
            {
                readToc(readingHandler);
            }
            return this.toc;

        }


        public void SetMetadataInfo(DBResult info)
        {
            this.authors = info.authors;
            SqlliteDB.Instance.updateEbookAuthors(this.Id, authors);

            this.description = info.physical_description;
            SqlliteDB.Instance.updateEbookDescription(this.Id,description);

            this.imageUrl = info.imageURL;
            SqlliteDB.Instance.updateEbookImageUrl(this.Id, imageUrl);

            this.isbn = info.isbn;
            SqlliteDB.Instance.updateEbookISBN(this.Id, isbn);

            this.publisher = info.publisher;
            SqlliteDB.Instance.updateEbookPublisher(this.Id, publisher);

            this.summary = info.summary;
            SqlliteDB.Instance.updateEbookSummary(this.Id, summary);

            this.title = info.title;
            SqlliteDB.Instance.updateEbookTitle(this.Id, title);

        }
        #endregion

        #region Other Functions
        /// <summary>
        /// Enregistre toutes les données concernant l'EBook
        /// </summary>
        public void saveEBook()
        {
            try
            {
                SqlliteDB.Instance.updateEBook(this.Id, this.Filepath, this.Title,
                    this.Authors, this.Publisher, this.Description, this.ISBN,
                    this.ImageUrl, this.Summary, this.Tags);
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
            }
        }

        /// <summary>
        /// Ajoute le tag s'il n'existe pas déjà
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        public bool addTag(string tag)
        {
            try
            {
                if (!this.Tags.Contains(tag))
                    this.Tags.Add(tag);
                return true;
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
                return false;
            }
        }

        /// <summary>
        /// Enlève le tag
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        public bool removeTag(string tag)
        {
            try
            {
                this.Tags.Remove(tag);
                return true;
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
                return false;
            }
        }

        /// <summary>
        /// Transforme l'instance de l'objet au format XML
        /// </summary>
        /// <returns></returns>
        public string toXML()
        {
            try
            {
                StringBuilder result = new StringBuilder();
                result.Append(string.Concat("<ebook id=", this.Id.ToString(), " filepath=", this.Filepath));
                result.AppendLine(string.Concat(" size=", this.SizeToString, " >"));

                result.AppendLine(string.Concat("<title>", this.Title, "</title>"));
                result.AppendLine(string.Concat("<authors>", this.Authors, "</authors>"));
                result.AppendLine(string.Concat("<publisher>", this.Publisher, "</publisher>"));
                result.AppendLine(string.Concat("<description>", this.Description, "</description>"));
                result.AppendLine(string.Concat("<isbn>", this.ISBN, "</isbn>"));
                result.AppendLine(string.Concat("<imageurl>", this.ImageUrl, "</imageurl>"));
                result.AppendLine(string.Concat("<summary>", this.Summary, "</summary>"));
                result.AppendLine(string.Concat(this.getTOC(null)));

                result.AppendLine("<tags>");
                foreach (string tag in this.Tags)
                {
                    result.AppendLine(string.Concat("<tag>", tag, "</tag>"));
                }
                result.AppendLine("</tags>");

                result.AppendLine("</ebook>");

                return result.ToString();
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
                return string.Empty;
            }
        }

        /// <summary>
        /// fonction permettant de lire la table des matières d'un ebook
        /// </summary>
        /// <param name="cB"></param>
        /// <returns></returns>
        abstract public bool readToc(IEBookReadingHandler cB);
        #endregion

        #region Test Functions
        public bool isOnDisk()
        {
            try
            {
                return File.Exists(this.Filepath);
            }
            catch (Exception ex)
            {
                this.log.Error("", ex);
                throw ex;
            }
        }
        #endregion
    }
}
